package com.yykj.hospital.server.service.banci.impl;

import com.yykj.common.constant.CommonConstant;
import com.yykj.common.enums.BanCiType;
import com.yykj.common.enums.HospitalOnlineTypeEnum;
import com.yykj.common.enums.ResultEnums;
import com.yykj.common.exception.NormalException;
import com.yykj.hospital.server.dto.banci.patient.client.AppointDayInfo;
import com.yykj.hospital.server.dto.banci.patient.client.AppointDayTimeInfo;
import com.yykj.hospital.server.dto.banci.patient.client.DoctorBanCiListDTO;
import com.yykj.hospital.server.dto.banci.patient.client.DoctorBanCiListDetailDTO;
import com.yykj.hospital.server.form.BanCiSearchForm;
import com.yykj.hospital.server.model.entity.HospitalDoctor;
import com.yykj.hospital.server.model.entity.banci.HospitalDoctorBanCi;
import com.yykj.hospital.server.model.entity.banci.HospitalDoctorVisitLevel;
import com.yykj.hospital.server.model.repository.HospitalDoctorRepository;
import com.yykj.hospital.server.model.repository.banci.HospitalBanCiRepository;
import com.yykj.hospital.server.model.repository.banci.HospitalDoctorBanCiRepository;
import com.yykj.hospital.server.model.repository.banci.HospitalDoctorVisitLevelRepository;
import com.yykj.hospital.server.service.banci.BanCiSearchService;
import com.yykj.hospital.server.service.banci.PatientClientBanCiService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class PatientClientBanCiServiceImpl implements PatientClientBanCiService {
    @Override
    public List<DoctorBanCiListDTO> patientClientViewAppointmentBanCi(BanCiSearchForm form) {
        if (form.getHospitalId() == null || form.getHospitalId() <= 0 ||
                form.getDepId() == null || form.getDepId() <= 0) {
            throw new NormalException(ResultEnums.PARAM_ERROR);
        }
        List<HospitalDoctor> doctorList = doctorRepository.findAllByHospitalIdAndDepIdAndEnableStatus(form.getHospitalId(), form.getDepId(), true);
        Map<String, HospitalDoctor> doctorMap = new HashMap<>();
        for (HospitalDoctor doctor : doctorList) {
            doctorMap.put(doctor.getDoctorId(), doctor);
        }

        List<HospitalDoctorVisitLevel> levelList = levelRepository.findAllByHospitalId(form.getHospitalId());

        List<HospitalDoctorBanCi> doctorBanCiList = searchService.searchBanCi(form);
        List<DoctorBanCiListDTO> result = new ArrayList<>();

        for (HospitalDoctorVisitLevel level : levelList) {
            DoctorBanCiListDTO dto = new DoctorBanCiListDTO();
            dto.setLevelName(level.getName());
            dto.setLevelId(level.getId());
            Map<String, DoctorBanCiListDetailDTO> map = new HashMap<>();
            for (HospitalDoctorBanCi doctorBanCi : doctorBanCiList) {
                HospitalDoctor doctor = doctorMap.get(doctorBanCi.getDoctorId());
                if (doctor.getEnableStatus() && doctorBanCi.getLevelId().equals(level.getId())) {
                    DoctorBanCiListDetailDTO detailDTO = map.get(doctor.getDoctorId());
                    if (detailDTO == null) {
                        detailDTO = new DoctorBanCiListDetailDTO();
                        detailDTO.setAvailable(false);
                        BeanUtils.copyProperties(doctor, detailDTO);
                        dto.getList().add(detailDTO);
                        map.put(doctor.getDoctorId(), detailDTO);

                    }
                    if (doctorBanCi.getAppointment() > doctorBanCi.getAppointmentUsed()) {
                        detailDTO.setAvailable(true);
                    }

                }
            }
            result.add(dto);
        }

        for (DoctorBanCiListDTO dto : result) {
            dto.getList().removeIf(next -> !next.getAvailable());
        }


        return result;
    }

    @Override
    public List<AppointDayInfo> listDoctorAppointDayInfo(String doctorId, Integer levelId) {
        HospitalDoctor doctor = doctorRepository.findById(doctorId).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        BanCiSearchForm form = BanCiSearchForm.builder()
                .hospitalId(doctor.getHospitalId())
                .doctorId(doctorId)
                .depId(doctor.getDepId())
                .levelId(levelId)
                .baseTime(LocalDateTime.now())
                .type(BanCiType.appointment)
                .build();
        List<HospitalDoctorBanCi> doctorBanCiList = searchService.searchBanCi(form);
        List<AppointDayInfo> result = new ArrayList<>();
        Map<LocalDate, AppointDayInfo> map = new HashMap<>();
        for (HospitalDoctorBanCi doctorBanCi : doctorBanCiList) {
            AppointDayInfo info = map.get(doctorBanCi.getDay());
            if (info == null) {
                info = new AppointDayInfo();
                info.setDay(doctorBanCi.getDay());
                info.setStatus(0);
                result.add(info);
                map.put(doctorBanCi.getDay(), info);
            }
            if (1 != info.getStatus()) {
                if (doctorBanCi.getAppointment() != null && doctorBanCi.getAppointmentUsed() != null
                        && doctorBanCi.getAppointment() > doctorBanCi.getAppointmentUsed()) {
                    info.setStatus(1);
                } else {
                    info.setStatus(2);
                }
            }

        }
        return result;
    }

    @Override
    public List<AppointDayInfo> listDoctorOnlineDayInfo(String doctorId, HospitalOnlineTypeEnum type) {
        HospitalDoctor doctor = doctorRepository.findById(doctorId).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        BanCiSearchForm form = BanCiSearchForm.builder()
                .hospitalId(doctor.getHospitalId())
                .doctorId(doctorId)
                .depId(doctor.getDepId())
                .baseTime(LocalDateTime.now())
                .type(BanCiType.online)
                .build();
        List<HospitalDoctorBanCi> doctorBanCiList = searchService.searchBanCi(form);
        List<AppointDayInfo> result = new ArrayList<>();
        Map<LocalDate, AppointDayInfo> map = new HashMap<>();
        for (HospitalDoctorBanCi doctorBanCi : doctorBanCiList) {
            AppointDayInfo info = map.get(doctorBanCi.getDay());
            if (info == null) {
                info = new AppointDayInfo();
                info.setDay(doctorBanCi.getDay());
                info.setStatus(0);
                result.add(info);
                map.put(doctorBanCi.getDay(), info);
            }

            if (1 != info.getStatus()) {
                switch (type) {
                    case pic:
                        if (doctorBanCi.getPic() != null && doctorBanCi.getPicUsed() != null
                                && doctorBanCi.getPic() > doctorBanCi.getPicUsed()) {
                            info.setStatus(1);
                        }
                        break;
                    case video:
                        if (doctorBanCi.getVideo() != null && doctorBanCi.getVideoUsed() != null
                                && doctorBanCi.getVideo() > doctorBanCi.getVideoUsed()) {
                            info.setStatus(1);
                        }
                        break;
                    case voice:
                        if (doctorBanCi.getVoice() != null && doctorBanCi.getVideoUsed() != null
                                && doctorBanCi.getVoice() > doctorBanCi.getVideoUsed()) {
                            info.setStatus(1);
                        }
                        break;
                }
            }

            if (1 != info.getStatus()) {
                info.setStatus(2);
            }

        }
        return result;
    }

    @Override
    public List<AppointDayTimeInfo> listAppointDayTimeInfo(String doctorId, String strDay) {
        LocalDate day = LocalDate.parse(strDay, DateTimeFormatter.ofPattern("yyyy-MM-dd"));

        HospitalDoctor doctor = doctorRepository.findById(doctorId).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        LocalDateTime baseTime = LocalDateTime.now().plusMinutes(CommonConstant.BEFORE_APPOINTMENT_MINUTE);

        BanCiSearchForm form = BanCiSearchForm.builder()
                .hospitalId(doctor.getHospitalId())
                .doctorId(doctorId)
                .depId(doctor.getDepId())
                .day(day)
                .type(BanCiType.appointment)
                .build();
        List<HospitalDoctorBanCi> doctorBanCiList = searchService.searchBanCi(form);

        List<AppointDayTimeInfo> result = new ArrayList<>();
        for (HospitalDoctorBanCi doctorBanCi : doctorBanCiList) {
            AppointDayTimeInfo info = new AppointDayTimeInfo();
            BeanUtils.copyProperties(doctorBanCi, info);
            info.setRemain(doctorBanCi.getAppointment() - doctorBanCi.getAppointmentUsed());
            info.setAppointId(doctorBanCi.getId());
            info.setStatus(0);

            if (day.isAfter(baseTime.toLocalDate()) || (day.equals(baseTime.toLocalDate()) && doctorBanCi.getStartTime().isAfter(baseTime.toLocalTime()))) {
                if (doctorBanCi.getAppointment() == null || doctorBanCi.getAppointmentUsed() == null) {
                    info.setStatus(0);
                } else {
                    if (doctorBanCi.getAppointment() != null && doctorBanCi.getAppointmentUsed() != null
                            && doctorBanCi.getAppointment() > doctorBanCi.getAppointmentUsed()) {
                        info.setStatus(1);
                    } else {
                        info.setStatus(2);
                    }
                }
            }

            result.add(info);
        }
        return result;
    }

    @Override
    public List<AppointDayTimeInfo> listOnlineDayTimeInfo(String doctorId, String strDay, HospitalOnlineTypeEnum type) {
        LocalDate day = LocalDate.parse(strDay, DateTimeFormatter.ofPattern("yyyy-MM-dd"));

        HospitalDoctor doctor = doctorRepository.findById(doctorId).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        LocalDateTime baseTime = LocalDateTime.now().plusMinutes(CommonConstant.BEFORE_APPOINTMENT_MINUTE);

        BanCiSearchForm form = BanCiSearchForm.builder()
                .hospitalId(doctor.getHospitalId())
                .doctorId(doctorId)
                .depId(doctor.getDepId())
                .day(day)
                .type(BanCiType.online)
                .build();
        List<HospitalDoctorBanCi> doctorBanCiList = searchService.searchBanCi(form);

        List<AppointDayTimeInfo> result = new ArrayList<>();
        for (HospitalDoctorBanCi doctorBanCi : doctorBanCiList) {

            AppointDayTimeInfo info = new AppointDayTimeInfo();
            BeanUtils.copyProperties(doctorBanCi, info);
            info.setAppointId(doctorBanCi.getId());
            info.setStatus(0);

            if (day.isAfter(baseTime.toLocalDate()) || ( day.equals(baseTime.toLocalDate()) && doctorBanCi.getStartTime().isAfter(baseTime.toLocalTime()))) {

                switch (type) {
                    case pic:
                        if (doctorBanCi.getPic() != null && doctorBanCi.getPicUsed() != null
                                && doctorBanCi.getPic() > doctorBanCi.getPicUsed()) {
                            info.setStatus(1);
                            info.setRemain(doctorBanCi.getPic() - doctorBanCi.getPicUsed());
                        }
                        break;
                    case video:
                        if (doctorBanCi.getVideo() != null && doctorBanCi.getVideoUsed() != null
                                && doctorBanCi.getVideo() > doctorBanCi.getVideoUsed()) {
                            info.setStatus(1);
                            info.setRemain(doctorBanCi.getVideo() - doctorBanCi.getVideoUsed());
                        }
                        break;
                    case voice:
                        if (doctorBanCi.getVoice() != null && doctorBanCi.getVideoUsed() != null
                                && doctorBanCi.getVoice() > doctorBanCi.getVideoUsed()) {
                            info.setStatus(1);
                            info.setRemain(doctorBanCi.getVoice() - doctorBanCi.getVideoUsed());
                        }
                        break;
                }

                if (1 != info.getStatus()) {
                    info.setStatus(2);
                }
            }
            result.add(info);
        }
        return result;
    }


    private HospitalDoctorRepository doctorRepository;

    private HospitalDoctorVisitLevelRepository levelRepository;

    private BanCiSearchService searchService;

    @Autowired
    public void setDoctorRepository(HospitalDoctorRepository doctorRepository) {
        this.doctorRepository = doctorRepository;
    }

    @Autowired
    public void setLevelRepository(HospitalDoctorVisitLevelRepository levelRepository) {
        this.levelRepository = levelRepository;
    }

    @Autowired
    public void setSearchService(BanCiSearchService searchService) {
        this.searchService = searchService;
    }
}
